﻿using System;
using System.Collections.Generic;
using System.Linq;
using DataScripter.Containers;
using DataScripter.Database;
using DataScripter.Database.SqlServer;
using DataScripter.Scripting.Compare.InsideSqlServer.Data;
using DataScripter.Scripting.InputSources;
using DataScripter.Scripting.Processes.Output;
using DataScripter.Sorters;

namespace DataScripter.Scripting.Processes
{
    class CompareSqlServerDataProcess : BaseProcess
    {
        private SqlServerDb LeftDb { get; set; }
        private SqlServerDb RightDb { get; set; }
        private IDatabaseStructure LeftDatabase { get; set; }
        private IDatabaseStructure RightDatabase { get; set; }

        private IEnumerable<ITableStructure> LeftTablesToCompare { get; set; }
        private IEnumerable<ITableStructure> RightTablesToCompare { get; set; }

        public CompareSqlServerDataProcess(string name, IContainer container) 
            : base(name, container)
        {
        }


        public override void Initialize(Dictionary<string, string> parameters)
        {
            ISqlServerInputSource leftSqlServer = Container.Resolve<ISqlServerInputSource>(parameters["Left"]);
            leftSqlServer.Initialize();
            LeftDb = leftSqlServer.Db;
            ISqlServerInputSource rightSqlServer = Container.Resolve<ISqlServerInputSource>(parameters["Right"]);
            rightSqlServer.Initialize();
            RightDb = rightSqlServer.Db;
            LeftDatabase = leftSqlServer.Resolve<IDatabaseStructure>();
            RightDatabase = rightSqlServer.Resolve<IDatabaseStructure>();

            //TODO: support schema's
            bool tablesSupplied = parameters.ContainsKey("TablesToCompare");
            if (tablesSupplied)
            {
                LeftTablesToCompare = GetTables(parameters["TablesToCompare"], LeftDatabase);
                RightTablesToCompare = GetTables(parameters["TablesToCompare"], RightDatabase);
            }
            else
            {
                LeftTablesToCompare = LeftDatabase.GetTableNames().Select(LeftDatabase.GetTable).ToList();
                RightTablesToCompare = RightDatabase.GetTableNames().Select(RightDatabase.GetTable).ToList();
            }
        }

        private IEnumerable<ITableStructure> GetTables(string tablesToCompareParameter, IDatabaseStructure databaseStructure)
        {
            return tablesToCompareParameter.Split(',').Select(databaseStructure.GetTable);
        }

        public override IProcessOutput Run()
        {
            RunParents();
            if (State == ProcessState.Error)
                return null;

            DataComparisonProcessOutput sqlOutput = new DataComparisonProcessOutput();
            Output = sqlOutput;

            foreach (ITableStructure leftTableStructure in new TableStructureSorterFirstWithoutIncomingForeignKeys(LeftDatabase).Sort(LeftTablesToCompare))
            {
                ITableStructure rightTableStructure = RightTablesToCompare.FirstOrDefault(ts => ts.TableName == leftTableStructure.TableName);
                if (rightTableStructure == null)
                    continue;

                RecordsInserter inserter = new RecordsInserter(RightDb, LeftDatabase, leftTableStructure, RightDatabase, rightTableStructure);
                //TODO: support for different table structure
                //TODO: support for different field names
                //TODO: support for unique keys

                string sql = inserter.Sql;

                sqlOutput.Sql = string.IsNullOrEmpty(sqlOutput.Sql)
                                    ? sql
                                    : sqlOutput.Sql + Environment.NewLine + sql;

            }

            foreach (ITableStructure leftTableStructure in new TableStructureSorterFirstWithoutIncomingForeignKeys(LeftDatabase).Sort(LeftTablesToCompare))
            {
                ITableStructure rightTableStructure = RightTablesToCompare.FirstOrDefault(ts => ts.TableName == leftTableStructure.TableName);
                if (rightTableStructure == null)
                    continue;

                RecordsUpdater updater = new RecordsUpdater(RightDb, LeftDatabase, leftTableStructure, RightDatabase, rightTableStructure);
                //TODO: support for different table structure
                //TODO: support for different field names
                //TODO: support for unique keys

                string sql = updater.Sql;

                sqlOutput.Sql = string.IsNullOrEmpty(sqlOutput.Sql)
                                    ? sql
                                    : sqlOutput.Sql + Environment.NewLine + sql;

            }

            foreach (ITableStructure leftTableStructure in new TableStructureSorterFirstWithoutIncomingForeignKeys(LeftDatabase).Sort(LeftTablesToCompare))
            {
                ITableStructure rightTableStructure = RightTablesToCompare.FirstOrDefault(ts => ts.TableName == leftTableStructure.TableName);
                if (rightTableStructure == null)
                    continue;

                RecordsDeleter deleter = new RecordsDeleter(RightDb, LeftDatabase, leftTableStructure, RightDatabase, rightTableStructure);
                //TODO: support for different table structure
                //TODO: support for different field names
                //TODO: support for unique keys

                string sql = deleter.Sql;

                sqlOutput.Sql = string.IsNullOrEmpty(sqlOutput.Sql)
                                    ? sql
                                    : sqlOutput.Sql + Environment.NewLine + sql;

            }

            return Output;
        }
    }
}
